<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>N4455RNone: No Sane Compiler Would Optimize Atomics</title>
<style data-fill-with="stylesheet">/******************************************************************************
 *                   Style sheet for the W3C specifications                   *
 *
 * Special classes handled by this style sheet include:
 *
 * Indices
 *   - .toc for the Table of Contents (<ol class="toc">)
 *     + <span class="secno"> for the section numbers
 *   - #toc for the Table of Contents (<nav id="toc">)
 *   - ul.index for Indices (<a href="#ref">term</a><span>, in §N.M</span>)
 *   - table.index for Index Tables (e.g. for properties or elements)
 *
 * Structural Markup
 *   - table.data for general data tables
 *     -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results !
 *     -> use <table class='complex data'> for extra-complex tables
 *     -> use <td class='long'> for paragraph-length cell content
 *     -> use <td class='pre'> when manual line breaks/indentation would help readability
 *   - dl.switch for switch statements
 *   - ol.algorithm for algorithms (helps to visualize nesting)
 *   - .figure and .caption (HTML4) and figure and figcaption (HTML5)
 *     -> .sidefigure for right-floated figures
 *   - ins/del
 *
 * Code
 *   - pre and code
 *
 * Special Sections
 *   - .note       for informative notes             (div, p, span, aside, details)
 *   - .example    for informative examples          (div, p, pre, span)
 *   - .issue      for issues                        (div, p, span)
 *   - .assertion  for assertions                    (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *
 * Definition Boxes
 *   - pre.def   for WebIDL definitions
 *   - table.def for tables that define other entities (e.g. CSS properties)
 *   - dl.def    for definition lists that define other entitles (e.g. HTML elements)
 *
 * Numbering
 *   - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>)
 *   - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>)
 *   - ::before styled for CSS-generated issue/example/figure numbers:
 *     -> Documents wishing to use this only need to add
 *        figcaption::before,
 *        .caption::before { content: "Figure "  counter(figure) " ";  }
 *        .example::before { content: "Example " counter(example) " "; }
 *        .issue::before   { content: "Issue "   counter(issue) " ";   }
 *
 * Header Stuff (ignore, just don't conflict with these classes)
 *   - .head for the header
 *   - .copyright for the copyright
 *
 * Miscellaneous
 *   - .overlarge for things that should be as wide as possible, even if
 *     that overflows the body text area. This can be used on an item or
 *     on its container, depending on the effect desired.
 *     Note that this styling basically doesn't help at all when printing,
 *     since A4 paper isn't much wider than the max-width here.
 *     It's better to design things to fit into a narrower measure if possible.
 *   - js-added ToC jump links (see fixup.js)
 *
 ******************************************************************************/

/******************************************************************************/
/*                                   Body                                     */
/******************************************************************************/

	body {
		counter-reset: example figure issue;

		/* Layout */
		max-width: 50em;               /* limit line length to 50em for readability   */
		margin: 0 auto;                /* center text within page                     */
		padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */
		padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag     */

		/* Typography */
		line-height: 1.5;
		font-family: sans-serif;
		widows: 2;
		orphans: 2;
		word-wrap: break-word;
		overflow-wrap: break-word;
		hyphens: auto;

		/* Colors */
		color: black;
		background: white top left fixed no-repeat;
		background-size: 25px auto;
	}


/******************************************************************************/
/*                         Front Matter & Navigation                          */
/******************************************************************************/

/** Header ********************************************************************/

	div.head { margin-bottom: 1em }
	div.head hr { border-style: solid; }

	div.head h1 {
		font-weight: bold;
		margin: 0 0 .1em;
		font-size: 220%;
	}

	div.head h2 { margin-bottom: 1.5em;}

/** W3C Logo ******************************************************************/

	.head .logo {
		float: right;
		margin: 0.4rem 0 0.2rem .4rem;
	}

	.head img[src*="logos/W3C"] {
		display: block;
		border: solid #1a5e9a;
		border-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		color: white;
		font-weight: bold;
	}

	.head a:hover > img[src*="logos/W3C"],
	.head a:focus > img[src*="logos/W3C"] {
		opacity: .8;
	}

	.head a:active > img[src*="logos/W3C"] {
		background: #c00;
		border-color: #c00;
	}

	/* see also additional rules in Link Styling section */

/** Copyright *****************************************************************/

	p.copyright,
	p.copyright small { font-size: small }

/** Back to Top / ToC Toggle **************************************************/

	@media print {
		#toc-nav {
			display: none;
		}
	}
	@media not print {
		#toc-nav {
			position: fixed;
			z-index: 2;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
			color: black;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

			height: 1.33em;
			padding: .1em 0.3em;
			margin: 0;

			background: white;
			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;
			background: white;
		}
		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		#toc-nav > a:hover,
		#toc-nav > a:focus {
			background: #f8f8f8;
		}
		#toc-nav > a:not(:hover):not(:focus) {
			color: #707070;
		}

		/* statusbar gets in the way on keyboard focus; remove once browsers fix */
		#toc-nav > a[href="#toc"]:not(:hover):focus:last-child {
			padding-bottom: 1.5rem;
		}

		#toc-nav:not(:hover) > a:not(:focus) > span + span {
			/* Ideally this uses :focus-within on #toc-nav */
			display: none;
		}
		#toc-nav > a > span + span {
			padding-right: 0.2em;
		}

		#toc-toggle-inline {
			vertical-align: 0.05em;
			font-size: 80%;
			color: gray;
			color: hsla(203,20%,40%,.7);
			border-style: none;
			background: transparent;
			position: relative;
		}
		#toc-toggle-inline:hover:not(:active),
		#toc-toggle-inline:focus:not(:active) {
			text-shadow: 1px 1px silver;
			top: -1px;
			left: -1px;
		}

		#toc-nav :active {
			color: #C00;
		}
	}

/** ToC Sidebar ***************************************************************/

	/* Floating sidebar */
	@media screen {
		body.toc-sidebar #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			max-width: 80%;
			max-width: calc(100% - 2em - 26px);
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
		}
		body.toc-sidebar #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
		}
		body.toc-sidebar #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	/* Hide main scroller when only the ToC is visible anyway */
	@media screen and (max-width: 28em) {
		body.toc-sidebar {
			overflow: hidden;
		}
	}

	/* Sidebar with its own space */
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
		}
		body:not(.toc-inline) #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
		}

		body:not(.toc-inline) {
			padding-left: 29em;
		}
		/* See also Overflow section at the bottom */

		body:not(.toc-inline) #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) {
			margin: 0 4em;
		}
	}

/******************************************************************************/
/*                                Sectioning                                  */
/******************************************************************************/

/** Headings ******************************************************************/

	h1, h2, h3, h4, h5, h6, dt {
		page-break-after: avoid;
		page-break-inside: avoid;
		font: 100% sans-serif;   /* Reset all font styling to clear out UA styles */
		font-family: inherit;    /* Inherit the font family. */
		line-height: 1.2;        /* Keep wrapped headings compact */
		hyphens: manual;         /* Hyphenated headings look weird */
	}

	h2, h3, h4, h5, h6 {
		margin-top: 3rem;
	}

	h1, h2, h3 {
		color: #005A9C;
		background: transparent;
	}

	h1 { font-size: 170%; }
	h2 { font-size: 140%; }
	h3 { font-size: 120%; }
	h4 { font-weight: bold; }
	h5 { font-style: italic; }
	h6 { font-variant: small-caps; }
	dt { font-weight: bold; }

/** Subheadings ***************************************************************/

	h1 + h2,
	#subtitle {
		/* #subtitle is a subtitle in an H2 under the H1 */
		margin-top: 0;
	}
	h2 + h3,
	h3 + h4,
	h4 + h5,
	h5 + h6 {
		margin-top: 1.2em; /* = 1 x line-height */
	}

/** Section divider ***********************************************************/

	:not(.head) > hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		border: transparent solid 0;
		background: transparent;
	}
	:not(.head) > hr::before {
		content: "\2727\2003\2003\2727\2003\2003\2727";
	}

/******************************************************************************/
/*                            Paragraphs and Lists                            */
/******************************************************************************/

	p {
		margin: 1em 0;
	}

	dd > p:first-child,
	li > p:first-child {
		margin-top: 0;
	}

	ul, ol {
		margin-left: 0;
		padding-left: 2em;
	}

	li {
		margin: 0.25em 0 0.5em;
		padding: 0;
	}

	dl dd {
		margin: 0 0 .5em 2em;
	}

	.head dd + dd { /* compact for header */
		margin-top: -.5em;
	}

	/* Style for algorithms */
	ol.algorithm ol:not(.algorithm),
	.algorithm > ol ol:not(.algorithm) {
	 border-left: 0.5em solid #DEF;
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	  padding: .5em;
	  border: thin solid #ddd; border-radius: .5em;
	  margin: .5em calc(-0.5em - 1px);
	}
	[data-algorithm]:not(.heading) > :first-child {
	  margin-top: 0;
	}
	[data-algorithm]:not(.heading) > :last-child {
	  margin-bottom: 0;
	}

	/* Style for switch/case <dl>s */
	dl.switch > dd > ol.only,
	dl.switch > dd > .only > ol {
	 margin-left: 0;
	}
	dl.switch > dd > ol.algorithm,
	dl.switch > dd > .algorithm > ol {
	 margin-left: -2em;
	}
	dl.switch {
	 padding-left: 2em;
	}
	dl.switch > dt {
	 text-indent: -1.5em;
	 margin-top: 1em;
	}
	dl.switch > dt + dt {
	 margin-top: 0;
	}
	dl.switch > dt::before {
	 content: '\21AA';
	 padding: 0 0.5em 0 0;
	 display: inline-block;
	 width: 1em;
	 text-align: right;
	 line-height: 0.5em;
	}

/** Terminology Markup ********************************************************/


/******************************************************************************/
/*                                 Inline Markup                              */
/******************************************************************************/

/** Terminology Markup ********************************************************/
	dfn   { /* Defining instance */
		font-weight: bolder;
	}
	a > i { /* Instance of term */
		font-style: normal;
	}
	dt dfn code, code.idl {
		font-size: medium;
	}
	dfn var {
		font-style: normal;
	}

/** Change Marking ************************************************************/

	del { color: red;  text-decoration: line-through; }
	ins { color: #080; text-decoration: underline;    }

/** Miscellaneous improvements to inline formatting ***************************/

	sup {
		vertical-align: super;
		font-size: 80%
	}

/******************************************************************************/
/*                                    Code                                    */
/******************************************************************************/

/** General monospace/pre rules ***********************************************/

	pre, code, samp {
		font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
		font-size: .9em;
		page-break-inside: avoid;
		hyphens: none;
		text-transform: none;
	}
	pre code,
	code code {
		font-size: 100%;
	}

	pre {
		margin-top: 1em;
		margin-bottom: 1em;
		overflow: auto;
	}

/** Inline Code fragments *****************************************************/

  /* Do something nice. */

/******************************************************************************/
/*                                    Links                                   */
/******************************************************************************/

/** General Hyperlinks ********************************************************/

	/* We hyperlink a lot, so make it less intrusive */
	a[href] {
		color: #034575;
		text-decoration: none;
		border-bottom: 1px solid #707070;
		/* Need a bit of extending for it to look okay */
		padding: 0 1px 0;
		margin: 0 -1px 0;
	}
	a:visited {
		border-bottom-color: #BBB;
	}

	/* Use distinguishing colors when user is interacting with the link */
	a[href]:focus,
	a[href]:hover {
		background: #f8f8f8;
		background: rgba(75%, 75%, 75%, .25);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	a[href]:active {
		color: #C00;
		border-color: #C00;
	}

	/* Backout above styling for W3C logo */
	.head .logo,
	.head .logo a {
		border: none;
		text-decoration: none;
		background: transparent;
	}

/******************************************************************************/
/*                                    Images                                  */
/******************************************************************************/

	img {
		border-style: none;
	}

	/* For autogen numbers, add
	   .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; }
	*/

	figure, .figure, .sidefigure {
		page-break-inside: avoid;
		text-align: center;
		margin: 2.5em 0;
	}
	.figure img,    .sidefigure img,    figure img,
	.figure object, .sidefigure object, figure object {
		max-width: 100%;
		margin: auto;
	}
	.figure pre, .sidefigure pre, figure pre {
		text-align: left;
		display: table;
		margin: 1em auto;
	}
	.figure table, figure table {
		margin: auto;
	}
	@media screen and (min-width: 20em) {
		.sidefigure {
			float: right;
			width: 50%;
			margin: 0 0 0.5em 0.5em
		}
	}
	.caption, figcaption, caption {
		font-style: italic;
		font-size: 90%;
	}
	.caption::before, figcaption::before, figcaption > .marker {
		font-weight: bold;
	}
	.caption, figcaption {
		counter-increment: figure;
	}

	/* DL list is indented 2em, but figure inside it is not */
	dd > .figure, dd > figure { margin-left: -2em }

/******************************************************************************/
/*                             Colored Boxes                                  */
/******************************************************************************/

	.issue, .note, .example, .assertion, .advisement, blockquote {
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	.issue,
	.note,
	.example,
	.advisement,
	.assertion,
	blockquote {
		margin: 1em auto;
	}
	.note  > p:first-child,
	.issue > p:first-child,
	blockquote > :first-child {
		margin-top: 0;
	}
	blockquote > :last-child {
		margin-bottom: 0;
	}

/** Blockquotes ***************************************************************/

	blockquote {
		border-color: silver;
	}

/** Open issue ****************************************************************/

	.issue {
		border-color: #E05252;
		background: #FBE9E9;
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		text-transform: uppercase;
		color: #AE1E1E;
		padding-right: 1em;
		text-transform: uppercase;
	}
	/* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers,
	   or use class="marker" to mark up the issue number in source. */

/** Example *******************************************************************/

	.example {
		border-color: #E0CB52;
		background: #FCFAEE;
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		text-transform: uppercase;
		color: #827017;
		min-width: 7.5em;
		display: block;
	}
	/* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers,
	   or use class="marker" to mark up the example number in source. */

/** Non-normative Note ********************************************************/

	.note {
		border-color: #52E052;
		background: #E9FBE9;
		overflow: auto;
	}

	.note::before, .note > .marker,
	details.note > summary::before,
	details.note > summary > .marker {
		text-transform: uppercase;
		display: block;
		color: hsl(120, 70%, 30%);
	}
	/* Add .note::before { content: "Note"; } for autogen label,
	   or use class="marker" to mark up the label in source. */

	details.note > summary {
		display: block;
		color: hsl(120, 70%, 30%);
	}
	details.note[open] > summary {
		border-bottom: 1px silver solid;
	}

/** Assertion Box *************************************************************/
	/*  for assertions in algorithms */

	.assertion {
		border-color: #AAA;
		background: #EEE;
	}

/** Advisement Box ************************************************************/
	/*  for attention-grabbing normative statements */

	.advisement {
		border-color: orange;
		border-style: none solid;
		background: #FFEECC;
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement > .marker {
		color: #B35F00;
	}

/** Spec Obsoletion Notice ****************************************************/
	/* obnoxious obsoletion notice for older/abandoned specs. */

	details {
		display: block;
	}
	summary {
		font-weight: bolder;
	}

	.annoying-warning:not(details),
	details.annoying-warning:not([open]) > summary,
	details.annoying-warning[open] {
		background: #fdd;
		color: red;
		font-weight: bold;
		padding: .75em 1em;
		border: thick red;
		border-style: solid;
		border-radius: 1em;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

@media not print {
	details.annoying-warning[open] {
		position: fixed;
		left: 1em;
		right: 1em;
		bottom: 1em;
		z-index: 1000;
	}
}

	details.annoying-warning:not([open]) > summary {
		text-align: center;
	}

/** Entity Definition Boxes ***************************************************/

	.def {
		padding: .5em 1em;
		background: #DEF;
		margin: 1.2em 0;
		border-left: 0.5em solid #8CCBF2;
	}

/******************************************************************************/
/*                                    Tables                                  */
/******************************************************************************/

	th, td {
		text-align: left;
		text-align: start;
	}

/** Property/Descriptor Definition Tables *************************************/

	table.def {
		/* inherits .def box styling, see above */
		width: 100%;
		border-spacing: 0;
	}

	table.def td,
	table.def th {
		padding: 0.5em;
		vertical-align: baseline;
		border-bottom: 1px solid #bbd7e9;
	}

	table.def > tbody > tr:last-child th,
	table.def > tbody > tr:last-child td {
		border-bottom: 0;
	}

	table.def th {
		font-style: italic;
		font-weight: normal;
		padding-left: 1em;
		width: 3em;
	}

	/* For when values are extra-complex and need formatting for readability */
	table td.pre {
		white-space: pre-wrap;
	}

	/* A footnote at the bottom of a def table */
	table.def           td.footnote {
		padding-top: 0.6em;
	}
	table.def           td.footnote::before {
		content: " ";
		display: block;
		height: 0.6em;
		width: 4em;
		border-top: thin solid;
	}

/** Data tables (and properly marked-up index tables) *************************/
	/*
		 <table class="data"> highlights structural relationships in a table
		 when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute)

		 Use class="complex data" for particularly complicated tables --
		 (This will draw more lines: busier, but clearer.)

		 Use class="long" on table cells with paragraph-like contents
		 (This will adjust text alignment accordingly.)
		 Alternately use class="longlastcol" on tables, to have the last column assume "long".
	*/

	table {
		word-wrap: normal;
		overflow-wrap: normal;
		hyphens: manual;
	}

	table.data,
	table.index {
		margin: 1em auto;
		border-collapse: collapse;
		border: hidden;
		width: 100%;
	}
	table.data caption,
	table.index caption {
		max-width: 50em;
		margin: 0 auto 1em;
	}

	table.data td,  table.data th,
	table.index td, table.index th {
		padding: 0.5em 1em;
		border-width: 1px;
		border-color: silver;
		border-top-style: solid;
	}

	table.data thead td:empty {
		padding: 0;
		border: 0;
	}

	table.data  thead,
	table.index thead,
	table.data  tbody,
	table.index tbody {
		border-bottom: 2px solid;
	}

	table.data colgroup,
	table.index colgroup {
		border-left: 2px solid;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		border-right: 2px solid;
		border-top: 1px solid silver;
		padding-right: 1em;
	}

	table.data th[colspan],
	table.data td[colspan] {
		text-align: center;
	}

	table.complex.data th,
	table.complex.data td {
		border: 1px solid silver;
		text-align: center;
	}

	table.data.longlastcol td:last-child,
	table.data td.long {
	 vertical-align: baseline;
	 text-align: left;
	}

	table.data img {
		vertical-align: middle;
	}


/*
Alternate table alignment rules

	table.data,
	table.index {
		text-align: center;
	}

	table.data  thead th[scope="row"],
	table.index thead th[scope="row"] {
		text-align: right;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		text-align: right;
	}

Possible extra rowspan handling

	table.data  tbody th[rowspan]:not([rowspan='1']),
	table.index tbody th[rowspan]:not([rowspan='1']),
	table.data  tbody td[rowspan]:not([rowspan='1']),
	table.index tbody td[rowspan]:not([rowspan='1']) {
		border-left: 1px solid silver;
	}

	table.data  tbody th[rowspan]:first-child,
	table.index tbody th[rowspan]:first-child,
	table.data  tbody td[rowspan]:first-child,
	table.index tbody td[rowspan]:first-child{
		border-left: 0;
		border-right: 1px solid silver;
	}
*/

/******************************************************************************/
/*                                  Indices                                   */
/******************************************************************************/


/** Table of Contents *********************************************************/

	.toc a {
		/* More spacing; use padding to make it part of the click target. */
		padding-top: 0.1rem;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Reverse color scheme */
		color: black;
		border-color: #3980B5;
		border-bottom-width: 3px !important;
		margin-bottom: 0px !important;
	}
	.toc a:visited {
		border-color: #054572;
	}
	.toc a:not(:focus):not(:hover) {
		/* Allow colors to cascade through from link styling */
		border-bottom-color: transparent;
	}

	.toc, .toc ol, .toc ul, .toc li {
		list-style: none; /* Numbers must be inlined into source */
		/* because generated content isn't search/selectable and markers can't do multilevel yet */
		margin:  0;
		padding: 0;
		line-height: 1.1rem; /* consistent spacing */
	}

	/* ToC not indented until third level, but font style & margins show hierarchy */
	.toc > li             { font-weight: bold;   }
	.toc > li li          { font-weight: normal; }
	.toc > li li li       { font-size:   95%;    }
	.toc > li li li li    { font-size:   90%;    }
	.toc > li li li li .secno { font-size: 85%; }
	.toc > li li li li li { font-size:   85%;    }
	.toc > li li li li li .secno { font-size: 100%; }

	/* @supports not (display:grid) { */
		.toc > li             { margin: 1.5rem 0;    }
		.toc > li li          { margin: 0.3rem 0;    }
		.toc > li li li       { margin-left: 2rem;   }

		/* Section numbers in a column of their own */
		.toc .secno {
			float: left;
			width: 4rem;
			white-space: nowrap;
		}

		.toc li {
			clear: both;
		}

		:not(li) > .toc              { margin-left:  5rem; }
		.toc .secno                  { margin-left: -5rem; }
		.toc > li li li .secno       { margin-left: -7rem; }
		.toc > li li li li .secno    { margin-left: -9rem; }
		.toc > li li li li li .secno { margin-left: -11rem; }

		/* Tighten up indentation in narrow ToCs */
		@media (max-width: 30em) {
			:not(li) > .toc              { margin-left:  4rem; }
			.toc .secno                  { margin-left: -4rem; }
			.toc > li li li              { margin-left:  1rem; }
			.toc > li li li .secno       { margin-left: -5rem; }
			.toc > li li li li .secno    { margin-left: -6rem; }
			.toc > li li li li li .secno { margin-left: -7rem; }
		}
	/* } */

	@supports (display:grid) and (display:contents) {
		/* Use #toc over .toc to override non-@supports rules. */
		#toc {
			display: grid;
			align-content: start;
			grid-template-columns: auto 1fr;
			grid-column-gap: 1rem;
			column-gap: 1rem;
			grid-row-gap: .6rem;
			row-gap: .6rem;
		}
		#toc h2 {
			grid-column: 1 / -1;
			margin-bottom: 0;
		}
		#toc ol,
		#toc li,
		#toc a {
			display: contents;
			/* Switch <a> to subgrid when supported */
		}
		#toc span {
			margin: 0;
		}
		#toc > .toc > li > a > span {
			/* The spans of the top-level list,
			   comprising the first items of each top-level section. */
			margin-top: 1.1rem;
		}
		#toc#toc .secno { /* Ugh, need more specificity to override base.css */
			grid-column: 1;
			width: auto;
			margin-left: 0;
		}
		#toc .content {
			grid-column: 2;
			width: auto;
			margin-right: 1rem;
		}
		#toc .content:hover {
			background: rgba(75%, 75%, 75%, .25);
			border-bottom: 3px solid #054572;
			margin-bottom: -3px;
		}
		#toc li li li .content {
			margin-left: 1rem;
		}
		#toc li li li li .content {
			margin-left: 2rem;
		}
	}


/** Index *********************************************************************/

	/* Index Lists: Layout */
	ul.index       { margin-left: 0; columns: 15em; text-indent: 1em hanging; }
	ul.index li    { margin-left: 0; list-style: none; break-inside: avoid; }
	ul.index li li { margin-left: 1em }
	ul.index dl    { margin-top: 0; }
	ul.index dt    { margin: .2em 0 .2em 20px;}
	ul.index dd    { margin: .2em 0 .2em 40px;}
	/* Index Lists: Typography */
	ul.index ul,
	ul.index dl { font-size: smaller; }
	@media not print {
		ul.index li span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
		}
	}

/** Index Tables *****************************************************/
	/* See also the data table styling section, which this effectively subclasses */

	table.index {
		font-size: small;
		border-collapse: collapse;
		border-spacing: 0;
		text-align: left;
		margin: 1em 0;
	}

	table.index td,
	table.index th {
		padding: 0.4em;
	}

	table.index tr:hover td:not([rowspan]),
	table.index tr:hover th:not([rowspan]) {
		background: #f7f8f9;
	}

	/* The link in the first column in the property table (formerly a TD) */
	table.index th:first-child a {
		font-weight: bold;
	}

/******************************************************************************/
/*                                    Print                                   */
/******************************************************************************/

	@media print {
		/* Pages have their own margins. */
		html {
			margin: 0;
		}
		/* Serif for print. */
		body {
			font-family: serif;
		}
	}
	@page {
		margin: 1.5cm 1.1cm;
	}

/******************************************************************************/
/*                                    Legacy                                  */
/******************************************************************************/

	/* This rule is inherited from past style sheets. No idea what it's for. */
	.hide { display: none }



/******************************************************************************/
/*                             Overflow Control                               */
/******************************************************************************/

	.figure .caption, .sidefigure .caption, figcaption {
		/* in case figure is overlarge, limit caption to 50em */
		max-width: 50rem;
		margin-left: auto;
		margin-right: auto;
	}
	.overlarge {
		/* Magic to create good table positioning:
		   "content column" is 50ems wide at max; less on smaller screens.
		   Extra space (after ToC + content) is empty on the right.

		   1. When table < content column, centers table in column.
		   2. When content < table < available, left-aligns.
		   3. When table > available, fills available + scroll bar.
		*/ 
		display: grid;
		grid-template-columns: minmax(0, 50em);
	}
	.overlarge > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-right: calc(13px + 26.5rem - 50vw);
			max-width: none;
		}
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) .overlarge {
			/* 30.5em body padding 50em content area */
			margin-right: calc(40em - 50vw) !important;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) .overlarge {
			/* 4em html margin 30.5em body padding 50em content area */
			margin-right: calc(84.5em - 100vw) !important;
		}
	}

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			 * http://lea.verou.me/2012/04/background-attachment-local/
			 *
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
			            top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
			            top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
			            top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
			            white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style type="text/css">
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      vertical-align: top;
    }
    th, td {
      border-left: none;
      border-right: none;
      padding: 0px 10px;
    }
    th {
      text-align: center;
    }

    del { background: #fcc; color: #000; text-decoration: line-through; }
    ins { background: #cfc; color: #000; }
    blockquote .highlight:not(.idl) { background: initial; margin: initial; padding: 0.5em }
    blockquote ul { background: inherit; }
    blockquote code.highlight:not(.idl) { padding: initial; }
    blockquote c-[a] { color: inherit; } /* Keyword.Declaration */
    blockquote c-[b] { color: inherit; } /* Keyword.Type */
    blockquote c-[c] { color: inherit; } /* Comment */
    blockquote c-[d] { color: inherit; } /* Comment.Multiline */
    blockquote c-[e] { color: inherit; } /* Name.Attribute */
    blockquote c-[f] { color: inherit; } /* Name.Tag */
    blockquote c-[g] { color: inherit; } /* Name.Variable */
    blockquote c-[k] { color: inherit; } /* Keyword */
    blockquote c-[l] { color: inherit; } /* Literal */
    blockquote c-[m] { color: inherit; } /* Literal.Number */
    blockquote c-[n] { color: inherit; } /* Name */
    blockquote c-[o] { color: inherit; } /* Operator */
    blockquote c-[p] { color: inherit; } /* Punctuation */
    blockquote c-[s] { color: inherit; } /* Literal.String */
    blockquote c-[t] { color: inherit; } /* Literal.String.Single */
    blockquote c-[u] { color: inherit; } /* Literal.String.Double */
    blockquote c-[cp] { color: inherit; } /* Comment.Preproc */
    blockquote c-[c1] { color: inherit; } /* Comment.Single */
    blockquote c-[cs] { color: inherit; } /* Comment.Special */
    blockquote c-[kc] { color: inherit; } /* Keyword.Constant */
    blockquote c-[kn] { color: inherit; } /* Keyword.Namespace */
    blockquote c-[kp] { color: inherit; } /* Keyword.Pseudo */
    blockquote c-[kr] { color: inherit; } /* Keyword.Reserved */
    blockquote c-[ld] { color: inherit; } /* Literal.Date */
    blockquote c-[nc] { color: inherit; } /* Name.Class */
    blockquote c-[no] { color: inherit; } /* Name.Constant */
    blockquote c-[nd] { color: inherit; } /* Name.Decorator */
    blockquote c-[ni] { color: inherit; } /* Name.Entity */
    blockquote c-[ne] { color: inherit; } /* Name.Exception */
    blockquote c-[nf] { color: inherit; } /* Name.Function */
    blockquote c-[nl] { color: inherit; } /* Name.Label */
    blockquote c-[nn] { color: inherit; } /* Name.Namespace */
    blockquote c-[py] { color: inherit; } /* Name.Property */
    blockquote c-[ow] { color: inherit; } /* Operator.Word */
    blockquote c-[mb] { color: inherit; } /* Literal.Number.Bin */
    blockquote c-[mf] { color: inherit; } /* Literal.Number.Float */
    blockquote c-[mh] { color: inherit; } /* Literal.Number.Hex */
    blockquote c-[mi] { color: inherit; } /* Literal.Number.Integer */
    blockquote c-[mo] { color: inherit; } /* Literal.Number.Oct */
    blockquote c-[sb] { color: inherit; } /* Literal.String.Backtick */
    blockquote c-[sc] { color: inherit; } /* Literal.String.Char */
    blockquote c-[sd] { color: inherit; } /* Literal.String.Doc */
    blockquote c-[se] { color: inherit; } /* Literal.String.Escape */
    blockquote c-[sh] { color: inherit; } /* Literal.String.Heredoc */
    blockquote c-[si] { color: inherit; } /* Literal.String.Interpol */
    blockquote c-[sx] { color: inherit; } /* Literal.String.Other */
    blockquote c-[sr] { color: inherit; } /* Literal.String.Regex */
    blockquote c-[ss] { color: inherit; } /* Literal.String.Symbol */
    blockquote c-[vc] { color: inherit; } /* Name.Variable.Class */
    blockquote c-[vg] { color: inherit; } /* Name.Variable.Global */
    blockquote c-[vi] { color: inherit; } /* Name.Variable.Instance */
    blockquote c-[il] { color: inherit; } /* Literal.Number.Integer.Long */
  </style>
  <link href="http://wg21.link/n4455" rel="canonical">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
<style>/* style-md-lists */

/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}</style>
<style>/* style-counters */

body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}</style>
<style>/* style-syntax-highlighting */

.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
c-[a] { color: #990055 } /* Keyword.Declaration */
c-[b] { color: #990055 } /* Keyword.Type */
c-[c] { color: #708090 } /* Comment */
c-[d] { color: #708090 } /* Comment.Multiline */
c-[e] { color: #0077aa } /* Name.Attribute */
c-[f] { color: #669900 } /* Name.Tag */
c-[g] { color: #222222 } /* Name.Variable */
c-[k] { color: #990055 } /* Keyword */
c-[l] { color: #000000 } /* Literal */
c-[m] { color: #000000 } /* Literal.Number */
c-[n] { color: #0077aa } /* Name */
c-[o] { color: #999999 } /* Operator */
c-[p] { color: #999999 } /* Punctuation */
c-[s] { color: #a67f59 } /* Literal.String */
c-[t] { color: #a67f59 } /* Literal.String.Single */
c-[u] { color: #a67f59 } /* Literal.String.Double */
c-[cp] { color: #708090 } /* Comment.Preproc */
c-[c1] { color: #708090 } /* Comment.Single */
c-[cs] { color: #708090 } /* Comment.Special */
c-[kc] { color: #990055 } /* Keyword.Constant */
c-[kn] { color: #990055 } /* Keyword.Namespace */
c-[kp] { color: #990055 } /* Keyword.Pseudo */
c-[kr] { color: #990055 } /* Keyword.Reserved */
c-[ld] { color: #000000 } /* Literal.Date */
c-[nc] { color: #0077aa } /* Name.Class */
c-[no] { color: #0077aa } /* Name.Constant */
c-[nd] { color: #0077aa } /* Name.Decorator */
c-[ni] { color: #0077aa } /* Name.Entity */
c-[ne] { color: #0077aa } /* Name.Exception */
c-[nf] { color: #0077aa } /* Name.Function */
c-[nl] { color: #0077aa } /* Name.Label */
c-[nn] { color: #0077aa } /* Name.Namespace */
c-[py] { color: #0077aa } /* Name.Property */
c-[ow] { color: #999999 } /* Operator.Word */
c-[mb] { color: #000000 } /* Literal.Number.Bin */
c-[mf] { color: #000000 } /* Literal.Number.Float */
c-[mh] { color: #000000 } /* Literal.Number.Hex */
c-[mi] { color: #000000 } /* Literal.Number.Integer */
c-[mo] { color: #000000 } /* Literal.Number.Oct */
c-[sb] { color: #a67f59 } /* Literal.String.Backtick */
c-[sc] { color: #a67f59 } /* Literal.String.Char */
c-[sd] { color: #a67f59 } /* Literal.String.Doc */
c-[se] { color: #a67f59 } /* Literal.String.Escape */
c-[sh] { color: #a67f59 } /* Literal.String.Heredoc */
c-[si] { color: #a67f59 } /* Literal.String.Interpol */
c-[sx] { color: #a67f59 } /* Literal.String.Other */
c-[sr] { color: #a67f59 } /* Literal.String.Regex */
c-[ss] { color: #a67f59 } /* Literal.String.Symbol */
c-[vc] { color: #0077aa } /* Name.Variable.Class */
c-[vg] { color: #0077aa } /* Name.Variable.Global */
c-[vi] { color: #0077aa } /* Name.Variable.Instance */
c-[il] { color: #000000 } /* Literal.Number.Integer.Long */
</style>
<style>/* style-selflinks */

.heading, .issue, .note, .example, li, dt {
    position: relative;
}
a.self-link {
    position: absolute;
    top: 0;
    left: calc(-1 * (3.5rem - 26px));
    width: calc(3.5rem - 26px);
    height: 2em;
    text-align: center;
    border: none;
    transition: opacity .2s;
    opacity: .5;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }</style>
<style>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: #005a9c;
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">N4455RNone<br>No Sane Compiler Would Optimize Atomics</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Finding of the WG21, <time class="dt-updated" datetime="1970-01-01">1970-01-01</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="http://wg21.link/n4455">http://wg21.link/n4455</a>
     <dt>Author:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:jfb@google.com">JF Bastien</a> (<span class="p-org org">Google</span>)
     <dt>Project:
     <dd>ISO/IEC JTC1/SC22/WG21 14882: Programming Language — C++
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <div class="p-summary" data-fill-with="abstract">
   <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2>
   <p>False. Compilers do optimize atomics, memory accesses around atomics, and utilize architecture-specific knowledge. This paper illustrates a few such optimizations, and discusses their implications.</p>
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li>
     <a href="#Samples"><span class="secno">1</span> <span class="content">Sample Optimizations</span></a>
     <ol class="toc">
      <li><a href="#opt-on"><span class="secno">1.1</span> <span class="content">Optimizations on Atomics</span></a>
      <li><a href="#opt-around"><span class="secno">1.2</span> <span class="content">Optimizations Around Atomics</span></a>
      <li><a href="#mutex"><span class="secno">1.3</span> <span class="content">Mutex: Safer than Atomics?</span></a>
      <li><a href="#opt-without"><span class="secno">1.4</span> <span class="content">Optimizations without Atomics</span></a>
      <li><a href="#arch"><span class="secno">1.5</span> <span class="content">Architecture and Implementation Specific Optimizations</span></a>
      <li><a href="#volatile"><span class="secno">1.6</span> <span class="content">Volatility</span></a>
     </ol>
    <li>
     <a href="#takeaways"><span class="secno">2</span> <span class="content">Takeaways</span></a>
     <ol class="toc">
      <li><a href="#committee"><span class="secno">2.1</span> <span class="content">For the Standards Committee</span></a>
      <li><a href="#devs"><span class="secno">2.2</span> <span class="content">For Developers</span></a>
      <li><a href="#hw"><span class="secno">2.3</span> <span class="content">For Hardware vendors</span></a>
      <li><a href="#compiler"><span class="secno">2.4</span> <span class="content">For Compiler Writers</span></a>
     </ol>
    <li><a href="#acknowledgement"><span class="secno">3</span> <span class="content">Acknowledgement</span></a>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="Samples"><span class="secno">1. </span><span class="content">Sample Optimizations</span><a class="self-link" href="#Samples"></a></h2>
   <p>We list optimizations that are either implemented in LLVM, or will be readily
implemented. A general rule to keep in mind is that the compiler performs many
of its optimizations on and around atomics based on the <em>as-if</em> rule. This implies that the compiler can make operations <strong>more</strong> atomic as long as it doesn’t violate forward progress requirements, and can make
them <strong>less</strong> atomic as long as it doesn’t add non-benign race
which weren’t already present in the original program. Put another way, correct
programs must work under all executions an implementation is allowed to create.</p>
   <h3 class="heading settled" data-level="1.1" id="opt-on"><span class="secno">1.1. </span><span class="content">Optimizations on Atomics</span><a class="self-link" href="#opt-on"></a></h3>
   <p>Atomics themselves can be optimized. A non-contentious example is constant
propagation into atomics without other intervening atomics:</p>
<pre class="highlight"><c- b>void</c-> <c- nf>inc</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- n>y</c-><c- p>)</c-> <c- p>{</c->
  <c- o>*</c-><c- n>y</c-> <c- o>+=</c-> <c- mi>1</c-><c- p>;</c->
<c- p>}</c->

<c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>x</c-><c- p>;</c->
<c- b>void</c-> <c- nf>two</c-><c- p>()</c-> <c- p>{</c->
  <c- n>inc</c-><c- p>(</c-><c- o>&amp;</c-><c- n>x</c-><c- p>);</c->
  <c- n>inc</c-><c- p>(</c-><c- o>&amp;</c-><c- n>x</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>x</c-><c- p>;</c->
<c- b>void</c-> <c- nf>two</c-><c- p>()</c-> <c- p>{</c->
  <c- n>x</c-> <c- o>+=</c-> <c- mi>2</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>The above optimization adds atomicity but cannot hinder forward progress, and is
therefore correct. This leads to further optimizations such as using the locked <code class="highlight"><c- n>inc</c-></code>/<code class="highlight"><c- n>dec</c-></code> instructions instead of locked <code class="highlight"><c- n>add</c-></code>/<code class="highlight"><c- n>sub</c-></code> when adding/subtracting <code class="highlight"><c- mi>1</c-></code> to an
atomic on x86:</p>
<pre class="highlight"><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>x</c-><c- p>;</c->
<c- b>void</c-> <c- nf>inc</c-><c- p>(</c-><c- b>int</c-> <c- n>val</c-><c- p>)</c-> <c- p>{</c->
  <c- n>x</c-> <c- o>+=</c-> <c- mi>1</c-><c- p>;</c->
  <c- n>x</c-> <c- o>+=</c-> <c- n>val</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- nl>_Z3inci:</c->
  <c- e>lock</c-> <c- nf>incl</c-> <c- no>x</c-><c- p>(</c-><c- g>%rip</c-><c- p>)</c->
  <c- e>lock</c-> <c- nf>addl</c-> <c- g>%edi</c-><c- p>,</c-> <c- no>x</c-><c- p>(</c-><c- g>%rip</c-><c- p>)</c->
  <c- nf>retq</c->
</pre>
   <p>In a similar vein, some opportunities for strength reduction will show up
because non-trivial code gets inlined which then exposes fairly silly code, such
as in the following trivial example:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- b>bool</c-> <c- n>silly</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>expected</c-><c- p>,</c-> <c- n>T</c-> <c- n>desired</c-><c- p>)</c-> <c- p>{</c->
  <c- n>x</c-><c- o>-></c-><c- n>compare_exchange_strong</c-><c- p>(</c-><c- n>expected</c-><c- p>,</c-> <c- n>desired</c-><c- p>);</c-> <c- c1>// Inlined.</c->
  <c- k>return</c-> <c- n>expected</c-> <c- o>==</c-> <c- n>desired</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- b>bool</c-> <c- n>silly</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>expected</c-><c- p>,</c-> <c- n>T</c-> <c- n>desired</c-><c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- n>x</c-><c- o>-></c-><c- n>compare_exchange_strong</c-><c- p>(</c-><c- n>expected</c-><c- p>,</c-> <c- n>desired</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>The following works for any memory order but <code class="highlight"><c- n>release</c-></code> and <code class="highlight"><c- n>acq_rel</c-></code>:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- b>bool</c-> <c- n>optme</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>desired</c-><c- p>)</c-> <c- p>{</c->
  <c- n>T</c-> <c- n>expected</c-> <c- o>=</c-> <c- n>desired</c-><c- p>;</c->
  <c- k>return</c-> <c- n>x</c-><c- o>-></c-><c- n>compare_exchange_strong</c-><c- p>(</c-><c- n>expected</c-><c- p>,</c-> <c- n>desired</c->
    <c- n>std</c-><c- o>::</c-><c- n>memory_order_seq_cst</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- b>bool</c-> <c- n>optme</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>desired</c-><c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- n>x</c-><c- o>-></c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_seq_cst</c-><c- p>)</c-> <c- o>==</c-> <c- n>desired</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>The above optimization may require that the compiler mark the transformed load
as a <em>release sequence</em> as defined in section 1.10 of the C++ standard.</p>
   <p>Similarly, while keeping the resulting memory order stronger or equal to the
individual ones, the following can occur:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- n>T</c-> <c- n>optmetoo</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>y</c-><c- p>)</c-> <c- p>{</c->
  <c- n>T</c-> <c- n>z</c-> <c- o>=</c-> <c- n>x</c-><c- o>-></c-><c- n>load</c-><c- p>();</c->
  <c- n>x</c-><c- o>-></c-><c- n>store</c-><c- p>(</c-><c- n>y</c-><c- p>);</c->
  <c- k>return</c-> <c- n>z</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- n>T</c-> <c- n>optmetoo</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>y</c-><c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- n>x</c-><c- o>-></c-><c- n>exchange</c-><c- p>(</c-><c- n>y</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>This may not always pay off! In particular, architectures with weaker memory
models may benefit from having write-after-read operations to the same location
instead of having an atomic exchange.</p>
   <p>Other simple optimizations can also occur because of inlining and constant
propagation such as turning <code class="highlight"><c- n>atomic</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>fetch_and</c-><c- p>(</c-><c- o>~</c-><c- p>(</c-><c- n>T</c-><c- p>)</c-><c- mi>0</c-><c- p>)</c-></code> into <code class="highlight"><c- n>atomic</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>load</c-><c- p>()</c-></code>. The same applies for <code class="highlight"><c- n>fetch_or</c-><c- p>(</c-><c- mi>0</c-><c- p>)</c-></code> and <code class="highlight"><c- n>fetch_xor</c-><c- p>(</c-><c- mi>0</c-><c- p>)</c-></code>, as well as <code class="highlight"><c- n>fetch_and</c-><c- p>(</c-><c- mi>0</c-><c- p>)</c-></code> becoming <code class="highlight"><c- n>store</c-><c- p>(</c-><c- mi>0</c-><c- p>)</c-></code>.</p>
   <p>As a slightly different example, the value for <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_lock_free</c-></code> can be determined at compile time for some architectures, but for others the
compiler can’t know the value for all sub-architectures and cannot return a
compile-time constant. The compiler may be given a specific sub-architecture
flag to work around this (restricting which machines the code will execute
correctly on) or must defer to feature detection followed by patching when the
program is loaded. This is the case, for example, for x86’s <code class="highlight"><c- n>LOCK</c-> <c- n>CMPXCHG16B</c-></code> instruction which is used to implement lock-free 16-byte
operations.</p>
   <p>These optimizations aren’t traditionally performed when using inline assembly
and showcases the strengths of hoisting abstractions to the language level.</p>
   <p>The reader for <a href="https://en.wikipedia.org/wiki/Seqlock">seqlock</a> bounds ticket acquisition and release with a load and a fence. This lets the
data reads get reordered in-between ticket acquire/release by using <code class="highlight"><c- n>relaxed</c-></code> memory ordering for data. The algorithm retries if the
ticket changed or data was being modified by the writer:</p>
<pre class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>T</c-><c- o>></c-> <c- n>reader</c-><c- p>()</c-> <c- p>{</c->
  <c- n>T</c-> <c- n>d1</c-><c- p>,</c-> <c- n>d2</c-><c- p>;</c->
  <c- b>unsigned</c-> <c- n>seq0</c-><c- p>,</c-> <c- n>seq1</c-><c- p>;</c->
  <c- k>do</c-> <c- p>{</c->
    <c- n>seq0</c-> <c- o>=</c-> <c- n>seq</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_acquire</c-><c- p>);</c->
    <c- n>d1</c-> <c- o>=</c-> <c- n>data1</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
    <c- n>d2</c-> <c- o>=</c-> <c- n>data2</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
    <c- n>std</c-><c- o>::</c-><c- n>atomic_thread_fence</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_acquire</c-><c- p>);</c->
    <c- n>seq1</c-> <c- o>=</c-> <c- n>seq</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- p>}</c-> <c- k>while</c-> <c- p>(</c-><c- n>seq0</c-> <c- o>!=</c-> <c- n>seq1</c-> <c- o>||</c-> <c- n>seq0</c-> <c- o>&amp;</c-> <c- mi>1</c-><c- p>);</c->
  <c- k>return</c-> <c- p>{</c-><c- n>d1</c-><c- p>,</c-> <c- n>d2</c-><c- p>};</c->
<c- p>}</c->

<c- b>void</c-> <c- n>writer</c-><c- p>(</c-><c- n>T</c-> <c- n>d1</c-><c- p>,</c-> <c- n>T</c-> <c- n>d2</c-><c- p>)</c-> <c- p>{</c->
  <c- b>unsigned</c-> <c- n>seq0</c-> <c- o>=</c-> <c- n>seq</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- n>seq</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- n>seq0</c-> <c- o>+</c-> <c- mi>1</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- n>data1</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- n>d1</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_release</c-><c- p>);</c->
  <c- n>data2</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- n>d2</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_release</c-><c- p>);</c->
  <c- n>seq</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- n>seq0</c-> <c- o>+</c-> <c- mi>2</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_release</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>The reader’s last ticket load effectively act as a <code class="highlight"><c- n>release</c-></code> load,
which doesn’t exist in the current memory model but would better express the
intent of the code while allowing subsequent operations to be moved into the
critical section if profitable. Hans Boehm <a href="http://www.hpl.hp.com/techreports/2012/HPL-2012-68.pdf">suggests</a> using
a <code class="highlight"><c- n>release</c-></code> fetch-add of zero, and shows that on x86 the code can be
written as follows:</p>
<pre class="highlight"><c- n>T</c-> <c- n>d1</c-><c- p>,</c-> <c- n>d2</c-><c- p>;</c->
<c- b>unsigned</c-> <c- n>seq0</c-><c- p>,</c-> <c- n>seq1</c-><c- p>;</c->
<c- k>do</c-> <c- p>{</c->
  <c- n>seq0</c-> <c- o>=</c-> <c- n>seq</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_acquire</c-><c- p>);</c->
  <c- n>d1</c-> <c- o>=</c-> <c- n>data1</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- n>d2</c-> <c- o>=</c-> <c- n>data2</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- n>seq1</c-> <c- o>=</c-> <c- n>seq</c-><c- p>.</c-><c- n>fetch_add</c-><c- p>(</c-><c- mi>0</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_release</c-><c- p>);</c->
<c- p>}</c-> <c- k>while</c-> <c- p>(</c-><c- n>seq0</c-> <c- o>!=</c-> <c- n>seq1</c-> <c- o>||</c-> <c- n>seq0</c-> <c- o>&amp;</c-> <c- mi>1</c-><c- p>);</c->
</pre>
   <p>This rewritten code then generates the following x86 assembly:</p>
<pre class="highlight"><c- nl>.LBB0_1:</c->
      <c- nf>movl</c->    <c- no>seq</c-><c- p>(</c-><c- g>%rip</c-><c- p>),</c-> <c- g>%esi</c->
      <c- nf>movl</c->    <c- no>data1</c-><c- p>(</c-><c- g>%rip</c-><c- p>),</c-> <c- g>%ecx</c->
      <c- nf>movl</c->    <c- no>data2</c-><c- p>(</c-><c- g>%rip</c-><c- p>),</c-> <c- g>%eax</c->
      <c- nf>mfence</c->
      <c- nf>movl</c->    <c- no>seq</c-><c- p>(</c-><c- g>%rip</c-><c- p>),</c-> <c- g>%edi</c->
      <c- nf>movl</c->    <c- g>%esi</c-><c- p>,</c-> <c- g>%edx</c->
      <c- nf>andl</c->    <c- no>$1</c-><c- p>,</c-> <c- g>%edx</c->
      <c- nf>cmpl</c->    <c- g>%edi</c-><c- p>,</c-> <c- g>%esi</c->
      <c- nf>jne</c->     <c- no>.LBB0_1</c->
      <c- nf>testl</c->   <c- g>%edx</c-><c- p>,</c-> <c- g>%edx</c->
      <c- nf>jne</c->     <c- no>.LBB0_1</c->
</pre>
   <p>This x86 assembly reduces contention by replacing <code class="highlight"><c- n>fetch_add</c-></code>—an
instruction requiring exclusive cache line access—to a simple <code class="highlight"><c- n>movl</c-></code>. This optimization is currently only known to be correct on
x86, is probably correct for other architectures, and is <a href="https://reviews.llvm.org/D5091">currently implemented
in LLVM</a>.</p>
   <p>Similar to the above <code class="highlight"><c- n>release</c-></code> fetch-add of zero serving as a <code class="highlight"><c- n>release</c-></code> load, one could also use an <code class="highlight"><c- n>acquire</c-></code> exchange
when an <code class="highlight"><c- n>acquire</c-></code> store is desired.</p>
   <p>Traditional compiler optimizations, such as dead store elimination, can be
performed on atomic operations, even sequentially consistent ones. Optimizers
have to be careful to avoid doing so across synchronization points because
another thread of execution can observe or modify memory, which means that the
traditional optimizations have to consider more intervening instructions than
they usually would when considering optimizations to atomic operations. In the
case of dead store elimination it isn’t sufficient to prove that an atomic store
post-dominates and aliases another to eliminate the other store.</p>
   <p>A trickier example is fusion of <code class="highlight"><c- n>relaxed</c-></code> atomic operations, even
when interleaved:</p>
<pre class="highlight"><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>;</c->
<c- b>void</c-> <c- nf>relaxed</c-><c- p>()</c-> <c- p>{</c->
  <c- n>x</c-><c- p>.</c-><c- n>fetch_add</c-><c- p>(</c-><c- mi>1</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- n>y</c-><c- p>.</c-><c- n>fetch_add</c-><c- p>(</c-><c- mi>1</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- n>x</c-><c- p>.</c-><c- n>fetch_add</c-><c- p>(</c-><c- mi>1</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- n>y</c-><c- p>.</c-><c- n>fetch_add</c-><c- p>(</c-><c- mi>1</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>;</c->
<c- b>void</c-> <c- nf>relaxed</c-><c- p>()</c-> <c- p>{</c->
  <c- n>x</c-><c- p>.</c-><c- n>fetch_add</c-><c- p>(</c-><c- mi>2</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
  <c- n>y</c-><c- p>.</c-><c- n>fetch_add</c-><c- p>(</c-><c- mi>2</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>We aren’t aware of compilers performing this optimization yet, but <a href="https://llvm.org/bugs/show_bug.cgi?id=16477">it is being
discussed</a>. <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>atomic_signal_fence</c-></code> could be used to prevent
this reordering and fusion, or one could use a stronger memory ordering for the
operations: this optimization is only valid on relaxed operations which aren’t
ordered with respect to each other.</p>
   <p>A compiler can tag all functions on whether they have atomic instructions or
not, and optimize around call sites accordingly. This could even be done for all
virtual overrides when we can enumerate them, and can be used to carve out
different <a href="http://www.hpl.hp.com/techreports/2011/HPL-2011-57.pdf">inteference-free
regions</a>.</p>
   <p>Fence instructions are generated as a consequence of C++'s <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>atomic_thread_fence</c-></code> as well as, on some architectures, atomic
operations. Fence instructions tend to be expensive, and removing redundant ones
as well as positioning them optimally leads to great performance gains, while
keeping the code correct and simple. This is <a href="https://reviews.llvm.org/D5758">currently under review in LLVM</a>.</p>
   <p>Not all compiler optimizations are valid on atomics, this topic is still under <a href="http://www.di.ens.fr/~zappa/readings/c11comp.pdf">active research</a>.</p>
   <h3 class="heading settled" data-level="1.2" id="opt-around"><span class="secno">1.2. </span><span class="content">Optimizations Around Atomics</span><a class="self-link" href="#opt-around"></a></h3>
   <p>Compilers can optimize non-atomic memory accesses before and after atomic
accesses. A somewhat surprising example is that the following code can be (<a href="https://reviews.llvm.org/D4845">and is</a>!) transformed as shown, where <code class="highlight"><c- n>x</c-></code> is a non-atomic global.</p>
<pre class="highlight"><c- b>int</c-> <c- n>x</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
<c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>y</c-><c- p>;</c->
<c- b>int</c-> <c- nf>dso</c-><c- p>()</c-> <c- p>{</c->
  <c- n>x</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- b>int</c-> <c- n>z</c-> <c- o>=</c-> <c- n>y</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_seq_cst</c-><c- p>);</c->
  <c- n>y</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- mi>0</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_seq_cst</c-><c- p>);</c->
  <c- n>x</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c->
  <c- k>return</c-> <c- n>z</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- b>int</c-> <c- n>x</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
<c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>y</c-><c- p>;</c->
<c- b>int</c-> <c- nf>dso</c-><c- p>()</c-> <c- p>{</c->
  <c- c1>// Dead store eliminated.</c->
  <c- b>int</c-> <c- n>z</c-> <c- o>=</c-> <c- n>y</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_seq_cst</c-><c- p>);</c->
  <c- n>y</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- mi>0</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_seq_cst</c-><c- p>);</c->
  <c- n>x</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c->
  <c- k>return</c-> <c- n>z</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>The intuition behind the dead store elimination optimization is that the only
way another thread could have observed the dead store elimination is if their
code had been racy in the first place: only a <code class="highlight"><c- n>release</c-></code>/<code class="highlight"><c- n>acquire</c-></code> pair could have been synchronized with
another thread that observed the store (see <a href="http://www.di.ens.fr/~zappa/readings/pldi13.pdf">this paper</a> for
details). Sequentially consistent accesses are <code class="highlight"><c- n>acquire</c-></code>/<code class="highlight"><c- n>release</c-></code>, the key in this example is having the <code class="highlight"><c- n>release</c-></code> store come before the <code class="highlight"><c- n>acquire</c-></code> load and
synchronize with another thread (which the loop does by observing changes in <code class="highlight"><c- n>y</c-></code>).</p>
   <p>The following code, with a different store/load ordering and using <code class="highlight"><c- n>release</c-></code>/<code class="highlight"><c- n>acquire</c-></code> memory ordering, can also be
transformed as shown (but currently isn’t, at least in LLVM).</p>
<pre class="highlight"><c- b>int</c-> <c- n>x</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
<c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>y</c-><c- p>;</c->
<c- b>int</c-> <c- nf>rlo</c-><c- p>()</c-> <c- p>{</c->
  <c- n>x</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- n>y</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- mi>0</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_release</c-><c- p>);</c->
  <c- b>int</c-> <c- n>z</c-> <c- o>=</c-> <c- n>y</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_acquire</c-><c- p>);</c->
  <c- n>x</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c->
  <c- k>return</c-> <c- n>z</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- b>int</c-> <c- n>x</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
<c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>y</c-><c- p>;</c->
<c- b>int</c-> <c- nf>rlo</c-><c- p>()</c-> <c- p>{</c->
  <c- c1>// Dead store eliminated.</c->
  <c- n>y</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- mi>0</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_release</c-><c- p>);</c->
  <c- c1>// Redundant load eliminated.</c->
  <c- n>x</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c->
  <c- k>return</c-> <c- mi>0</c-><c- p>;</c-> <c- c1>// Stored value propagated here.</c->
<c- p>}</c->
</pre>
   <p>The above example’s load can be eliminated because there was no synchronization
with another thread: even if the <code class="highlight"><c- n>release</c-></code> is followed by an <code class="highlight"><c- n>acquire</c-></code> the compiler is allowed to assume that the stored value
wasn’t modified before the subsequent load, and that the load is therefore
redundant.</p>
   <p>Whereas the following code must (and does!) remain the same:</p>
<pre class="highlight"><c- b>int</c-> <c- n>x</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
<c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>y</c-><c- p>;</c->
<c- b>int</c-> <c- nf>no</c-><c- p>()</c-> <c- p>{</c->
  <c- n>x</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- n>y</c-><c- p>.</c-><c- n>store</c-><c- p>(</c-><c- mi>0</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_release</c-><c- p>);</c->
  <c- k>while</c-> <c- p>(</c-><c- o>!</c-><c- n>y</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_acquire</c-><c- p>));</c->
  <c- n>x</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c->
  <c- k>return</c-> <c- n>z</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Other optimizations such as global value ordering across atomics can be applied.</p>
   <h3 class="heading settled" data-level="1.3" id="mutex"><span class="secno">1.3. </span><span class="content">Mutex: Safer than Atomics?</span><a class="self-link" href="#mutex"></a></h3>
   <p>The same optimization potential applies to C++'s <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>mutex</c-></code>:
locking a mutex is equivalent to <code class="highlight"><c- n>acquire</c-></code> memory ordering, and
unlocking a mutex is equivalent to <code class="highlight"><c- n>release</c-></code> memory ordering. Using a
mutex correctly is slightly easier because the API is simpler than atomic’s API.</p>
   <p>Some current implementations rely on pthread’s mutex, which may not expose all
optimization opportunities because the compiler may not know how to handle the
slow-path futex (usually a syscall), or because the implementation is in a
different translation unit. The optimization difficulties can be overcome by
teaching the compiler to treat <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>mutex</c-></code> or pthread specially, or
by <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4195.pdf">making
it practical to implement mutexes in pure C++</a>. Optimization across
translation units, such as through link-time optimizations, or optimizations
relying on escape analysis, can also help expose more opportunities.</p>
   <h3 class="heading settled" data-level="1.4" id="opt-without"><span class="secno">1.4. </span><span class="content">Optimizations without Atomics</span><a class="self-link" href="#opt-without"></a></h3>
   <p>Another interesting optimization is to use potentially shared memory locations
(on the stack, heap and globals) as scratch storage, if the compiler can prove
that they are not accessed in other threads concurrently. This is spelled out in
the C++11 standard in section 1.10 ¶22. For example the following transformation
could occur:</p>
<pre class="highlight"><c- c1>// Some code, but no synchronization.</c->
<c- o>*</c-><c- n>p</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- c1>// Can be on stack, heap or global.</c->
</pre>
   <p>Becomes:</p>
<pre class="highlight"><c- c1>// ...</c->
<c- o>*</c-><c- n>p</c-> <c- o>=</c-> <c- n>RAX</c-><c- p>;</c-> <c- c1>// Spill temporary value.</c->
<c- c1>// ...</c->
<c- n>RAX</c-> <c- o>=</c-> <c- o>*</c-><c- n>p</c-><c- p>;</c-> <c- c1>// Restore temporary value.</c->
<c- c1>// ...</c->
<c- o>*</c-><c- n>p</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c->
</pre>
   <p>Since we write to <code class="highlight"><c- o>*</c-><c- n>p</c-></code> and there is no synchronization operations,
other threads do not read/write <code class="highlight"><c- o>*</c-><c- n>p</c-></code> without exercising undefined
behavior. We can therefore use it as scratch storage—and thus reduce stack frame
size—without changing the observable behavior of the program. This requires
escape analysis: the compiler must see the full scope of memory location <code class="highlight"><c- n>p</c-></code>, or must know that leaf functions don’t capture <code class="highlight"><c- n>p</c-></code> and aren’t used concurrently, for this optimization to be valid.</p>
   <h3 class="heading settled" data-level="1.5" id="arch"><span class="secno">1.5. </span><span class="content">Architecture and Implementation Specific Optimizations</span><a class="self-link" href="#arch"></a></h3>
   <p>Optimizations can sometimes be made per-architecture, or even per specific
implementation of an architecture. Compilers can usually be told to target
specific architectures, CPUs or attributes using flags such as <code class="highlight"><c- o>-</c-><c- n>march</c-></code>, <code class="highlight"><c- o>-</c-><c- n>mcpu</c-></code>, <code class="highlight"><c- o>-</c-><c- n>mattr</c-></code>.</p>
   <p>Spinloops are usually implemented with an <code class="highlight"><c- n>acquire</c-></code> load, which are
equivalent to a <code class="highlight"><c- n>relaxed</c-></code> load followed by an <code class="highlight"><c- n>acquire</c-></code> fence in the loop. On some architecture implementations it may make sense to
hoist the fence outside the loop, but how and when to do this is architecture
specific. In a similar way, mutexes usually want to be implemented as a spinloop
with exponential randomized backoff followed by a futex. The right
implementation of mutexes is highly platform-dependent.</p>
   <p>Instructions can also be implemented in manners that are nominally incorrect for
the architecture in general, but happen to be correct for specific
implementations of the architecture. For example, <code class="highlight"><c- n>release</c-></code> fences
should lower to <code class="highlight"><c- n>dmb</c-> <c- n>ish</c-></code> on ARM, but <a href="http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20130701/thread.html#179911">on
Apple’s Swift processor</a> they lower to <code class="highlight"><c- n>dmb</c-> <c- n>ishst</c-></code> instead, which
would be incorrect on other ARM processors. Some ARM processors can go even
further and remove all <code class="highlight"><c- n>dmb</c-></code> which aren’t system-wide because their
memory model is much stronger than ARM’s prescribed model.</p>
   <p>Some architectures support transactional memory. A compiler can use this
knowledge to make many consecutive atomic writes into a single atomic
transaction, and retry on commit failure. It can also speculate that many reads
and writes aren’t accessed concurrently, or that certain locks aren’t contended,
and fall back to a slow path, or to smaller transactions, if a commit failure
limit is reached. Such approaches have been implemented using Intel’s <a href="https://queue.acm.org/detail.cfm?id=2579227">RTM and HLE</a> extensions.</p>
   <p>Other architectures do dynamic binary translation behind the scenes, and also
use transactional memory. This can lead to further in-hardware optimizations as
well as fairly hard to predict behavior: sometimes races aren’t observed because
big transactions commit, and other times they do occur because transactions are
smaller. This certainly makes micro-benchmarking hard, if not impossible.</p>
   <p>The same applies for simulators and emulators which often just-in-time translate
the code they’re executing—leading to hard-to-predict behavior—and which also
often emulate multi-core systems using cooperative thread switching—leading to
predictable interleaving which is easier to optimize for the simulator.</p>
   <h3 class="heading settled" data-level="1.6" id="volatile"><span class="secno">1.6. </span><span class="content">Volatility</span><a class="self-link" href="#volatile"></a></h3>
   <p>Atomic operations are unsuitable to express that memory locations can be
externally modified. Indeed, <code class="highlight"><c- k>volatile</c-></code> (or <code class="highlight"><c- k>volatile</c-> <c- n>atomic</c-></code>) should be used in these circumstances.</p>
   <p>Shared memory isn’t explicitly defined by the C++ standard, yet programmers
often use operating system APIs to map the same physical memory location onto
multiple virtual addresses in the same process, or across processes. A
sufficiently advanced compiler, performing some of the optimizations described
above, can seriously harm code which uses shared memory naïvely.</p>
   <p>The C++ standard says that lock-free atomic operations must be <em>address
free</em> to address such issues, but this mandate isn’t normative.</p>
   <h2 class="heading settled" data-level="2" id="takeaways"><span class="secno">2. </span><span class="content">Takeaways</span><a class="self-link" href="#takeaways"></a></h2>
   <h3 class="heading settled" data-level="2.1" id="committee"><span class="secno">2.1. </span><span class="content">For the Standards Committee</span><a class="self-link" href="#committee"></a></h3>
   <p>Don’t assume that these optimizations don’t occur, but rather encourage
them. Standardize more common practice that enable to-the-metal
optimizations. Provide more libraries that make it easy to use concurrency and
parallelism and hard to get it wrong.</p>
   <h3 class="heading settled" data-level="2.2" id="devs"><span class="secno">2.2. </span><span class="content">For Developers</span><a class="self-link" href="#devs"></a></h3>
   <p>Drop assembly: it can’t be optimized as well and is only tuned to the
architectures that existed when you originally wrote the code. File bugs when
performance expectations aren’t met by the compiler. Suggest to the standard
committee new idiomatic patterns which enable concurrency and parallelism. Use
the tooling available to you, such as ThreadSanitizer, to find races in your
code.</p>
   <h3 class="heading settled" data-level="2.3" id="hw"><span class="secno">2.3. </span><span class="content">For Hardware vendors</span><a class="self-link" href="#hw"></a></h3>
   <p>Showcase your hardware’s strengths.</p>
   <h3 class="heading settled" data-level="2.4" id="compiler"><span class="secno">2.4. </span><span class="content">For Compiler Writers</span><a class="self-link" href="#compiler"></a></h3>
   <p>Get back to work, there’s so much more to optimize… and so much code to break!
Help users write good code: the compiler should provide diagnostics when it
detects anti-patterns or misuses of atomics.</p>
   <h2 class="heading settled" data-level="3" id="acknowledgement"><span class="secno">3. </span><span class="content">Acknowledgement</span><a class="self-link" href="#acknowledgement"></a></h2>
   <p>Thanks to Robin Morisset, Dmitry Vyukov, Chandler Carruth, Jeffrey Yasskin, Paul
McKenney, Lawrence Crowl, Hans Boehm and Torvald Riegel for their reviews,
corrections and ideas.</p>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

  var sidebarMedia = window.matchMedia('screen and (min-width: 78em)');
  var autoToggle   = function(e){ toggleSidebar(e.matches) };
  if(sidebarMedia.addListener) {
    sidebarMedia.addListener(autoToggle);
  }

  function toggleSidebar(on) {
    if (on == undefined) {
      on = !document.body.classList.contains('toc-sidebar');
    }

    /* Don’t scroll to compensate for the ToC if we’re above it already. */
    var headY = 0;
    var head = document.querySelector('.head');
    if (head) {
      // terrible approx of "top of ToC"
      headY += head.offsetTop + head.offsetHeight;
    }
    var skipScroll = window.scrollY < headY;

    var toggle = document.getElementById('toc-toggle');
    var tocNav = document.getElementById('toc');
    if (on) {
      var tocHeight = tocNav.offsetHeight;
      document.body.classList.add('toc-sidebar');
      document.body.classList.remove('toc-inline');
      toggle.innerHTML = collapseSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, 0 - tocHeight);
      }
      tocNav.focus();
      sidebarMedia.addListener(autoToggle); // auto-collapse when out of room
    }
    else {
      document.body.classList.add('toc-inline');
      document.body.classList.remove('toc-sidebar');
      toggle.innerHTML = expandSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, tocNav.offsetHeight);
      }
      if (toggle.matches(':hover')) {
        /* Unfocus button when not using keyboard navigation,
           because I don’t know where else to send the focus. */
        toggle.blur();
      }
    }
  }

  function createSidebarToggle() {
    /* Create the sidebar toggle in JS; it shouldn’t exist when JS is off. */
    var toggle = document.createElement('a');
      /* This should probably be a button, but appearance isn’t standards-track.*/
    toggle.id = 'toc-toggle';
    toggle.class = 'toc-toggle';
    toggle.href = '#toc';
    toggle.innerHTML = collapseSidebarText;

    sidebarMedia.addListener(autoToggle);
    var toggler = function(e) {
      e.preventDefault();
      sidebarMedia.removeListener(autoToggle); // persist explicit off states
      toggleSidebar();
      return false;
    }
    toggle.addEventListener('click', toggler, false);


    /* Get <nav id=toc-nav>, or make it if we don’t have one. */
    var tocNav = document.getElementById('toc-nav');
    if (!tocNav) {
      tocNav = document.createElement('p');
      tocNav.id = 'toc-nav';
      /* Prepend for better keyboard navigation */
      document.body.insertBefore(tocNav, document.body.firstChild);
    }
    /* While we’re at it, make sure we have a Jump to Toc link. */
    var tocJump = document.getElementById('toc-jump');
    if (!tocJump) {
      tocJump = document.createElement('a');
      tocJump.id = 'toc-jump';
      tocJump.href = '#toc';
      tocJump.innerHTML = tocJumpText;
      tocNav.appendChild(tocJump);
    }

    tocNav.appendChild(toggle);
  }

  var toc = document.getElementById('toc');
  if (toc) {
    createSidebarToggle();
    toggleSidebar(sidebarMedia.matches);

    /* If the sidebar has been manually opened and is currently overlaying the text
       (window too small for the MQ to add the margin to body),
       then auto-close the sidebar once you click on something in there. */
    toc.addEventListener('click', function(e) {
      if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) {
        toggleSidebar(false);
      }
    }, false);
  }
  else {
    console.warn("Can’t find Table of Contents. Please use <nav id='toc'> around the ToC.");
  }

  /* Wrap tables in case they overflow */
  var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index');
  var numTables = tables.length;
  for (var i = 0; i < numTables; i++) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'overlarge';
    table.parentNode.insertBefore(wrapper, table);
    wrapper.appendChild(table);
  }

})();
</script>